package com.atguigu.bean;

import com.atguigu.anno.Bean;
import com.atguigu.anno.Di;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class AnnotationApplicationContext implements ApplicationContext {

    private static String rootPath;
    private Map<Class, Object> beanFactory = new HashMap<>();

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    public AnnotationApplicationContext(String basePackage) {
        try {
            // 扫描包，扫描到类，然后注册到容器中
            // 1、把"."替换成”/”
            String basePackageNew = basePackage.replaceAll("\\.", "\\\\");
            // 2、获取包绝对路径
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(basePackageNew);
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                // 3、获取包路径
                String path = URLDecoder.decode(url.getFile(), "UTF-8");
                rootPath = path.substring(0, path.length() - basePackage.length());
                // 4、获取包下所有类
                doScanner(path);
            }
            // 5、属性注入
            loadDi();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doScanner(String path) {
        try {
            File file = new File(path);
            for (File f : file.listFiles()) {
                if (f.isDirectory()) {
                    doScanner(f.getPath());
                } else {
                    String pathWithClass = f.getAbsolutePath().substring(rootPath.length() - 1, f.getAbsolutePath().length());
                    if (pathWithClass.endsWith(".class")) {
                        // 5、获取类名
                        String className = pathWithClass.replaceAll("\\\\", ".").
                                replace(".class", "");
                        Class clazz = Class.forName(className);
                        if (!clazz.isInterface()) {
                            if (clazz.isAnnotationPresent(Bean.class)) {
                                Object instance = clazz.getConstructor().newInstance();
                                // 6、注册到容器中
                                if (clazz.getInterfaces().length > 0) {
                                    beanFactory.put(clazz.getInterfaces()[0], instance);
                                } else {
                                    beanFactory.put(clazz, instance);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 属性注入
     */
    private void loadDi() throws IllegalAccessException {
        // 实例化对象在BEANFACTORY的MAP住集合里面
        // 1 遍历BEANFACTORY的MAP集合
        Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
        for (Map.Entry<Class, Object> entry : entries) {
            Class key = entry.getKey();
            Object obj = entry.getValue();
            Class clazz = obj.getClass();
            // 2 获取MAP集合每一个对象（value), 每个对象都要遍历属性（field）
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                // 3 判断属性是否被注解@Di修饰
                if (field.isAnnotationPresent(Di.class)) {
                    // 4 获取属性类型
                    Class fieldType = field.getType();
                    // 5 获取属性类型在BEANFACTORY的MAP集合
                    Object fieldInstance = beanFactory.get(fieldType);
                    // 6 如果是私有属性，设置属性的可访问性
                    field.setAccessible(true);
                    // 7 给属性赋值
                    field.set(obj, fieldInstance);
                }
            }
        }
    }
}
